﻿using System;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using Microsoft.Phone.Applications.Common; // For the AccelerometerHelper
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;


namespace IWantIn
{
    public partial class MainPage : PhoneApplicationPage
    {
        Setting<string> chosenAnimal = new Setting<string>("ChosenAnimal", "cow");

        bool upsideDown = false;

        // The start, middle, end, and length of the
        // verticle path that the animal moves along
        const double MAX_Y = 170;
        const double MIN_Y = -75;
        const double MID_Y = 47.5;
        const double LENGTH_Y = 245;

        // The start, middle, and end of the clockwise rotation of animal
        const double MAX_ANGLE_CW = 180;
        const double MIN_ANGLE_CW = 0;
        const double MID_ANGLE_CW = 90;

        // The start, middle, and end of the counter-clockwise rotation of animal
        const double MAX_ANGLE_CCW = -180;
        const double MIN_ANGLE_CCW = 0;
        const double MID_ANGLE_CCW = -90;

        // The length of the rotation, regalrdless of which direction
        const double LENGTH_ANGLE = 180;

        public MainPage()
        {
            InitializeComponent();

            // Use the accelerometer via Microsoft's helper
            AccelerometerHelper.Instance.ReadingChanged += Accelerometer_ReadingChanged;

            SoundEffects.Initialize();

            // Allow the app to run (producing sounds) even when the phone is locked.
            // Once disabled, you cannot re-enable the default behavior!
            PhoneApplicationService.Current.ApplicationIdleDetectionMode =
              IdleDetectionMode.Disabled;
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            // Restore the chosen animal
            ChangeAnimal();

            // Start the accelerometer with Microsoft's helper
            AccelerometerHelper.Instance.Active = true;

            // While on this page, don't allow the screen to auto-lock
            PhoneApplicationService.Current.UserIdleDetectionMode =
              IdleDetectionMode.Disabled;
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            // Restore the ability for the screen to auto-lock when on other pages
            PhoneApplicationService.Current.UserIdleDetectionMode =
              IdleDetectionMode.Enabled;
        }

        void ChangeAnimal()
        {
            switch (this.chosenAnimal.Value)
            {
                case "cow":
                    this.AnimalImage.Source = new BitmapImage(
                      new Uri("Images/cow.png", UriKind.Relative));
                    break;
                case "sheep":
                    this.AnimalImage.Source = new BitmapImage(
                      new Uri("Images/sheep.png", UriKind.Relative));
                    break;
                case "cat":
                    this.AnimalImage.Source = new BitmapImage(
                      new Uri("Images/cat.png", UriKind.Relative));
                    break;
            }
        }

        // Process data coming from the accelerometer
        void Accelerometer_ReadingChanged(object sender,
                                          AccelerometerHelperReadingEventArgs e)
        {
            // Transition to the UI thread
            this.Dispatcher.BeginInvoke(delegate()
            {
                // Move the animal vertically based on the vertical force
                this.AnimalTransform.TranslateY =
                  Clamp(MID_Y - LENGTH_Y * e.AverageAcceleration.Y, MIN_Y, MAX_Y);

                // Clear the upside-down flag, only when completely upright
                if (this.AnimalTransform.TranslateY == MAX_Y)
                    this.upsideDown = false;

                // Rotate the animal to always be upright
                if (e.AverageAcceleration.X <= 0)
                    this.AnimalTransform.Rotation = Clamp(MID_ANGLE_CW +
                      LENGTH_ANGLE * e.AverageAcceleration.Y, MIN_ANGLE_CW, MAX_ANGLE_CW);
                else
                    this.AnimalTransform.Rotation = Clamp(MID_ANGLE_CCW -
                      LENGTH_ANGLE * e.AverageAcceleration.Y, MIN_ANGLE_CCW, MAX_ANGLE_CCW);

                // Play the appropriate shake sound when shaken
                if (ShakeDetection.JustShook(e.OriginalEventArgs))
                {
                    switch (this.chosenAnimal.Value)
                    {
                        case "cow": SoundEffects.MooShake.Play(); break;
                        case "sheep": SoundEffects.BaaShake.Play(); break;
                        case "cat": SoundEffects.MeowShake.Play(); break;
                    }
                }

                // Play the normal sound when first turned upside-down
                if (!this.upsideDown && this.AnimalTransform.TranslateY == MIN_Y)
                {
                    this.upsideDown = true;
                    switch (this.chosenAnimal.Value)
                    {
                        case "cow": SoundEffects.Moo.Play(); break;
                        case "sheep": SoundEffects.Baa.Play(); break;
                        case "cat": SoundEffects.Meow.Play(); break;
                    }
                }
            });
        }

        // "Clamp" the incoming value so it's no lower than min & no larger than max
        static double Clamp(double value, double min, double max)
        {
            return Math.Max(min, Math.Min(max, value));
        }

        // Application bar handlers

        void AnimalMenuItem_Click(object sender, EventArgs e)
        {
            this.chosenAnimal.Value = (sender as IApplicationBarMenuItem).Text;
            ChangeAnimal();
        }

        void InstructionsMenuItem_Click(object sender, EventArgs e)
        {
            this.NavigationService.Navigate(new Uri("/InstructionsPage.xaml",
              UriKind.Relative));
        }

        void CalibrateMenuItem_Click(object sender, EventArgs e)
        {
            this.NavigationService.Navigate(new Uri(
              "/Shared/Calibrate/CalibratePage.xaml?appName=IWantIn", UriKind.Relative));
        }

    }
}